home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 June / CHIP Haziran 2001.iso / prog / haziran / 19 / setup.exe / data.z / p9080_lib.c < prev    next >
C/C++ Source or Header  |  2001-04-11  |  32KB  |  1,040 lines

  1. ////////////////////////////////////////////////////////////////
  2. // File - P9080_LIB.C
  3. //
  4. // Library for 'WinDriver for PLX 9080' API. 
  5. // The basic idea is to get a handle for the board
  6. // with P9080_Open() and use it in the rest of the program
  7. // when calling WD functions.  Call P9080_Close() when done.
  8. // 
  9. ////////////////////////////////////////////////////////////////
  10.  
  11. #include "p9080_lib.h"
  12. #include "../../../include/windrvr_int_thread.h"
  13. #include <stdio.h>
  14.  
  15. // this string is set to an error message, if one occurs
  16. CHAR P9080_ErrorString[1024];
  17.  
  18. // internal data structures and enums
  19. enum { P9080_DMA_CHANNEL_SHIFT = 0x14 }; // shift in address between channels 0 and 1 of DMA
  20.  
  21. typedef struct P9080_DMA_STRUCT {
  22.     WD_DMA dma;
  23.     WD_DMA dmaList;
  24.     P9080_DMA_CHANNEL dmaChannel;
  25. } P9080_DMA_STRUCT;
  26.  
  27. enum { P9080_MODE_DESC       = 0xF9000140 };
  28. enum { P9080_MODE_DESC_BYTE  = 0x00000000 };
  29. enum { P9080_MODE_DESC_WORD  = 0x00010001 };
  30. enum { P9080_MODE_DESC_DWORD = 0x00030003 };
  31.  
  32. typedef struct
  33. {
  34.     WD_INTERRUPT Int;
  35.     HANDLE hThread;
  36.     WD_TRANSFER Trans[2];
  37.     P9080_INT_HANDLER funcIntHandler;
  38. } P9080_INTERRUPT;
  39.  
  40. typedef struct 
  41. {
  42.     DWORD dwLocalBase;
  43.     DWORD dwMask;
  44.     DWORD dwBytes;
  45.     DWORD dwAddr;
  46.     DWORD dwAddrDirect;
  47.     BOOL  fIsMemory;
  48. } P9080_ADDR_DESC;
  49.  
  50. typedef struct P9080_STRUCT
  51. {
  52.     HANDLE hWD;
  53.     WD_CARD cardLock;
  54.     WD_PCI_SLOT pciSlot;
  55.     WD_CARD_REGISTER cardReg;
  56.     P9080_ADDR_DESC addrDesc[AD_PCI_BARS];
  57.     DWORD  addrSpace;
  58.     BOOL   fUseInt;
  59.     P9080_INTERRUPT Int;
  60.     BOOL   fUseCS46EEPROM;
  61. } P9080_STRUCT;
  62.  
  63. // internal function used by P9080_Open()
  64. BOOL P9080_DetectCardElements(P9080_HANDLE hPlx);
  65. // internal function used by P9080_Read... and P9080_Write... functions
  66. void P9080_SetMode (P9080_HANDLE hPlx, P9080_MODE mode, DWORD dwLocalAddr);
  67.  
  68. DWORD P9080_CountCards (DWORD dwVendorID, DWORD dwDeviceID)
  69. {
  70.     WD_VERSION ver;
  71.     WD_PCI_SCAN_CARDS pciScan;
  72.     HANDLE hWD = INVALID_HANDLE_VALUE;
  73.  
  74.     P9080_ErrorString[0] = '\0';
  75.     hWD = WD_Open();
  76.     // check if handle valid & version OK
  77.     if (hWD==INVALID_HANDLE_VALUE) 
  78.     {
  79.         sprintf( P9080_ErrorString, "Failed opening " WD_PROD_NAME " device\n");
  80.         return 0;
  81.     }
  82.  
  83.     BZERO(ver);
  84.     WD_Version(hWD,&ver);
  85.     if (ver.dwVer<WD_VER) 
  86.     {
  87.         sprintf( P9080_ErrorString, "Incorrect " WD_PROD_NAME " version\n");
  88.         WD_Close (hWD);
  89.         return 0;
  90.     }
  91.  
  92.     BZERO(pciScan);
  93.     pciScan.searchId.dwVendorId = dwVendorID;
  94.     pciScan.searchId.dwDeviceId = dwDeviceID;
  95.     WD_PciScanCards (hWD, &pciScan);
  96.     WD_Close (hWD);
  97.     if (pciScan.dwCards==0)
  98.         sprintf( P9080_ErrorString, "no cards found\n");
  99.     return pciScan.dwCards;
  100. }
  101.  
  102.  
  103. BOOL P9080_Open (P9080_HANDLE *phPlx, DWORD dwVendorID, DWORD dwDeviceID, DWORD nCardNum, DWORD dwOptions)
  104. {
  105.     P9080_HANDLE hPlx = (P9080_HANDLE) malloc (sizeof (P9080_STRUCT));
  106.     DWORD dwIntStatus;
  107.  
  108.     WD_VERSION ver;
  109.     WD_PCI_SCAN_CARDS pciScan;
  110.     WD_PCI_CARD_INFO pciCardInfo;
  111.  
  112.     *phPlx = NULL;
  113.     P9080_ErrorString[0] = '\0';
  114.     BZERO(*hPlx);
  115.  
  116.     hPlx->hWD = WD_Open();
  117.  
  118.     // check if handle valid & version OK
  119.     if (hPlx->hWD==INVALID_HANDLE_VALUE) 
  120.     {
  121.         sprintf( P9080_ErrorString, "Failed opening " WD_PROD_NAME " device\n");
  122.         goto Exit;
  123.     }
  124.  
  125.     BZERO(ver);
  126.     WD_Version(hPlx->hWD,&ver);
  127.     if (ver.dwVer<WD_VER) 
  128.     {
  129.         sprintf( P9080_ErrorString, "Incorrect " WD_PROD_NAME " version\n");
  130.         goto Exit;
  131.     }
  132.  
  133.     BZERO(pciScan);
  134.     pciScan.searchId.dwVendorId = dwVendorID;
  135.     pciScan.searchId.dwDeviceId = dwDeviceID;
  136.     WD_PciScanCards (hPlx->hWD, &pciScan);
  137.     if (pciScan.dwCards==0) // Found at least one card
  138.     {
  139.         sprintf( P9080_ErrorString, "Could not find PCI card\n");
  140.         goto Exit;
  141.     }
  142.     if (pciScan.dwCards<=nCardNum)
  143.     {
  144.         sprintf( P9080_ErrorString, "Card out of range of available cards\n");
  145.         goto Exit;
  146.     }
  147.  
  148.     BZERO(pciCardInfo);
  149.     pciCardInfo.pciSlot = pciScan.cardSlot[nCardNum];
  150.     WD_PciGetCardInfo (hPlx->hWD, &pciCardInfo);
  151.     hPlx->pciSlot = pciCardInfo.pciSlot;
  152.     hPlx->cardReg.Card = pciCardInfo.Card;
  153.  
  154.     hPlx->fUseInt = (dwOptions & P9080_OPEN_USE_INT) ? TRUE : FALSE;
  155.     if (!hPlx->fUseInt)
  156.     {
  157.         DWORD i;
  158.         // Remove interrupt item if not needed
  159.         for (i=0; i<hPlx->cardReg.Card.dwItems; i++)
  160.         {
  161.             WD_ITEMS *pItem = &hPlx->cardReg.Card.Item[i];
  162.             if (pItem->item==ITEM_INTERRUPT)
  163.                 pItem->item = ITEM_NONE;
  164.         }
  165.     }
  166.     else
  167.     {
  168.         DWORD i;
  169.         // make interrupt resource sharable
  170.         for (i=0; i<hPlx->cardReg.Card.dwItems; i++)
  171.         {
  172.             WD_ITEMS *pItem = &hPlx->cardReg.Card.Item[i];
  173.             if (pItem->item==ITEM_INTERRUPT)
  174.                 pItem->fNotSharable = FALSE;
  175.         }
  176.     }
  177.  
  178.     hPlx->cardReg.fCheckLockOnly = FALSE;
  179.     WD_CardRegister (hPlx->hWD, &hPlx->cardReg);
  180.     if (hPlx->cardReg.hCard==0)
  181.     {
  182.         sprintf ( P9080_ErrorString, "Failed locking device\n");
  183.         goto Exit;
  184.     }
  185.  
  186.     if (!P9080_DetectCardElements(hPlx))
  187.     {
  188.         sprintf ( P9080_ErrorString, "Card does not have all items expected for PLX 9080\n");
  189.         goto Exit;
  190.     }
  191.  
  192.     // this enables target abort so it wont get stuck 
  193.     dwIntStatus = P9080_ReadReg (hPlx, P9080_INTCSR);
  194.     P9080_WriteReg (hPlx, P9080_INTCSR, dwIntStatus | BIT12);
  195.  
  196.     // check for EEPROM type
  197.     if( dwOptions & P9080_CS46_EEPROM )
  198.     {
  199.         hPlx->fUseCS46EEPROM = TRUE;
  200.     }
  201.  
  202.     // Open finished OK
  203.     *phPlx = hPlx;
  204.     return TRUE;
  205.  
  206. Exit:
  207.     // Error durin Open
  208.     if (hPlx->cardReg.hCard) 
  209.         WD_CardUnregister(hPlx->hWD, &hPlx->cardReg);
  210.     if (hPlx->hWD!=INVALID_HANDLE_VALUE)
  211.         WD_Close(hPlx->hWD);
  212.     free (hPlx);
  213.     return FALSE;
  214. }
  215.  
  216. void P9080_GetPciSlot(P9080_HANDLE hPlx, WD_PCI_SLOT *pPciSlot)
  217. {
  218.     *pPciSlot = hPlx->pciSlot;
  219. }
  220.  
  221.  
  222. DWORD P9080_ReadPCIReg(P9080_HANDLE hPlx, DWORD dwReg)
  223. {
  224.     WD_PCI_CONFIG_DUMP pciCnf;
  225.     DWORD dwVal;
  226.  
  227.     BZERO (pciCnf);
  228.     pciCnf.pciSlot = hPlx->pciSlot;
  229.     pciCnf.pBuffer = &dwVal;
  230.     pciCnf.dwOffset = dwReg;
  231.     pciCnf.dwBytes = 4;
  232.     pciCnf.fIsRead = TRUE;
  233.     WD_PciConfigDump(hPlx->hWD,&pciCnf);
  234.     return dwVal;
  235. }
  236.  
  237. void P9080_WritePCIReg(P9080_HANDLE hPlx, DWORD dwReg, DWORD dwData)
  238. {
  239.     WD_PCI_CONFIG_DUMP pciCnf;
  240.  
  241.     BZERO (pciCnf);
  242.     pciCnf.pciSlot = hPlx->pciSlot;
  243.     pciCnf.pBuffer = &dwData;
  244.     pciCnf.dwOffset = dwReg;
  245.     pciCnf.dwBytes = 4;
  246.     pciCnf.fIsRead = FALSE;
  247.     WD_PciConfigDump(hPlx->hWD,&pciCnf);
  248. }
  249.  
  250. BOOL P9080_DetectCardElements(P9080_HANDLE hPlx)
  251. {
  252.     DWORD i;
  253.     DWORD ad_sp;
  254.  
  255.     BZERO(hPlx->Int);
  256.     BZERO(hPlx->addrDesc);
  257.  
  258.     for (i=0; i<hPlx->cardReg.Card.dwItems; i++)
  259.     {
  260.         WD_ITEMS *pItem = &hPlx->cardReg.Card.Item[i];
  261.  
  262.         switch (pItem->item)
  263.         {
  264.         case ITEM_MEMORY:
  265.         case ITEM_IO:
  266.             {
  267.                 DWORD dwBytes;
  268.                 DWORD dwAddr;
  269.                 DWORD dwPhysAddr;
  270.                 DWORD dwAddrDirect = 0;
  271.                 BOOL fIsMemory;
  272.                 if (pItem->item==ITEM_MEMORY)
  273.                 {
  274.                     dwBytes = pItem->I.Mem.dwBytes;
  275.                     dwAddr = pItem->I.Mem.dwTransAddr;
  276.                     dwAddrDirect = pItem->I.Mem.dwUserDirectAddr;
  277.                     dwPhysAddr = pItem->I.Mem.dwPhysicalAddr;
  278.                     fIsMemory = TRUE;
  279.                 }
  280.                 else 
  281.                 {
  282.                     dwBytes = pItem->I.IO.dwBytes;
  283.                     dwAddr = pItem->I.IO.dwAddr;
  284.                     dwPhysAddr = dwAddr & 0xffff;
  285.                     fIsMemory = FALSE;
  286.                 }
  287.  
  288.                 for (ad_sp=P9080_ADDR_REG; ad_sp<=P9080_ADDR_EPROM; ad_sp++)
  289.                 {
  290.                     DWORD dwPCIAddr;
  291.                     DWORD dwPCIReg;
  292.  
  293.                     if (hPlx->addrDesc[ad_sp].dwAddr) continue;
  294.                     if (ad_sp==P9080_ADDR_REG) dwPCIReg = PCI_BAR0;
  295.                     else if (ad_sp<P9080_ADDR_EPROM) 
  296.                         dwPCIReg = PCI_BAR2 + 4*(ad_sp-P9080_ADDR_SPACE0);
  297.                     else dwPCIReg = PCI_ERBAR;
  298.                     dwPCIAddr = P9080_ReadPCIReg(hPlx, dwPCIReg);
  299.                     if (dwPCIAddr & 1)
  300.                     {
  301.                         if (fIsMemory) continue;
  302.                         dwPCIAddr &= ~0x3;
  303.                     }
  304.                     else
  305.                     {
  306.                         if (!fIsMemory) continue;
  307.                         dwPCIAddr &= ~0xf;
  308.                     }
  309.                     if (dwPCIAddr==dwPhysAddr)
  310.                         break;
  311.                 }
  312.                 if (ad_sp<=P9080_ADDR_EPROM)
  313.                 {
  314.                     DWORD j;
  315.                     hPlx->addrDesc[ad_sp].dwBytes = dwBytes;
  316.                     hPlx->addrDesc[ad_sp].dwAddr = dwAddr;
  317.                     hPlx->addrDesc[ad_sp].dwAddrDirect = dwAddrDirect;
  318.                     hPlx->addrDesc[ad_sp].fIsMemory = fIsMemory;
  319.                     hPlx->addrDesc[ad_sp].dwMask = 0;
  320.                     for (j=1; j<hPlx->addrDesc[ad_sp].dwBytes && j!=0x80000000; j *= 2)
  321.                     {
  322.                         hPlx->addrDesc[ad_sp].dwMask = 
  323.                             (hPlx->addrDesc[ad_sp].dwMask << 1) | 1;
  324.                     }
  325.                 }
  326.             }
  327.             break;
  328.         case ITEM_INTERRUPT:
  329.             if (hPlx->Int.Int.hInterrupt) return FALSE;
  330.             hPlx->Int.Int.hInterrupt = pItem->I.Int.hInterrupt;
  331.             break;
  332.         }
  333.     }
  334.  
  335.     // check that all the items needed were found
  336.     // check if interrupt found
  337.     if (hPlx->fUseInt && !hPlx->Int.Int.hInterrupt) 
  338.     {
  339.         return FALSE;
  340.     }
  341.  
  342.     // check that the registers space was found
  343.     if (!P9080_IsAddrSpaceActive(hPlx, P9080_ADDR_REG)) 
  344.             //|| hPlx->addrDesc[P9080_ADDR_REG].dwBytes!=P9080_RANGE_REG)
  345.         return FALSE;
  346.  
  347.     // use address space 0 for accessing local addresses
  348.     hPlx->addrSpace = P9080_ADDR_SPACE0;
  349.     
  350.     // check that address space 0 was found
  351.     if (!P9080_IsAddrSpaceActive(hPlx, hPlx->addrSpace)) return FALSE;
  352.  
  353.     return TRUE;
  354. }
  355.  
  356. void P9080_Close(P9080_HANDLE hPlx)
  357. {
  358.     // disable interrupts
  359.     if (P9080_IntIsEnabled(hPlx))
  360.         P9080_IntDisable(hPlx);
  361.  
  362.     // unregister card
  363.     if (hPlx->cardReg.hCard) 
  364.         WD_CardUnregister(hPlx->hWD, &hPlx->cardReg);
  365.  
  366.     // close WinDriver
  367.     WD_Close(hPlx->hWD);
  368.  
  369.     free (hPlx);
  370. }
  371.  
  372. BOOL P9080_IsAddrSpaceActive(P9080_HANDLE hPlx, P9080_ADDR addrSpace)
  373. {
  374.     return hPlx->addrDesc[addrSpace].dwAddr!=0;
  375. }
  376.  
  377. DWORD P9080_ReadReg (P9080_HANDLE hPlx, DWORD dwReg)
  378. {
  379.     return P9080_ReadDWord(hPlx, P9080_ADDR_REG, dwReg);
  380. }
  381.  
  382. void P9080_WriteReg (P9080_HANDLE hPlx, DWORD dwReg, DWORD dwData)
  383. {
  384.     P9080_WriteDWord(hPlx, P9080_ADDR_REG, dwReg, dwData);
  385. }
  386.  
  387. BYTE P9080_ReadByte (P9080_HANDLE hPlx, P9080_ADDR addrSpace, DWORD dwOffset)
  388. {
  389.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  390.     {
  391.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  392.         BYTE *pByte = (BYTE *) dwAddr;
  393.         return *pByte;
  394.     }
  395.     else
  396.     {
  397.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  398.         WD_TRANSFER trans;
  399.         BZERO(trans);
  400.         trans.cmdTrans = RP_BYTE;
  401.         trans.dwPort = dwAddr;
  402.         WD_Transfer (hPlx->hWD, &trans);
  403.         return trans.Data.Byte;
  404.     }
  405. }
  406.  
  407. void P9080_WriteByte (P9080_HANDLE hPlx, P9080_ADDR addrSpace, DWORD dwOffset, BYTE data)
  408. {
  409.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  410.     {
  411.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  412.         BYTE *pByte = (BYTE *) dwAddr;
  413.         *pByte = data;
  414.     }
  415.     else
  416.     {
  417.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  418.         WD_TRANSFER trans;
  419.         BZERO(trans);
  420.         trans.cmdTrans = WP_BYTE;
  421.         trans.dwPort = dwAddr;
  422.         trans.Data.Byte = data;
  423.         WD_Transfer (hPlx->hWD, &trans);
  424.     }
  425. }
  426.  
  427. WORD P9080_ReadWord (P9080_HANDLE hPlx, P9080_ADDR addrSpace, DWORD dwOffset)
  428. {
  429.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  430.     {
  431.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  432.         WORD *pWord = (WORD *) dwAddr;
  433.         return *pWord;
  434.     }
  435.     else
  436.     {
  437.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  438.         WD_TRANSFER trans;
  439.         BZERO(trans);
  440.         trans.cmdTrans = RP_WORD;
  441.         trans.dwPort = dwAddr;
  442.         WD_Transfer (hPlx->hWD, &trans);
  443.         return trans.Data.Word;
  444.     }
  445. }
  446.  
  447. void P9080_WriteWord (P9080_HANDLE hPlx, P9080_ADDR addrSpace, DWORD dwOffset, WORD data)
  448. {
  449.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  450.     {
  451.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  452.         WORD *pWord = (WORD *) dwAddr;
  453.         *pWord = data;
  454.     }
  455.     else
  456.     {
  457.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  458.         WD_TRANSFER trans;
  459.         BZERO(trans);
  460.         trans.cmdTrans = WP_WORD;
  461.         trans.dwPort = dwAddr;
  462.         trans.Data.Word = data;
  463.         WD_Transfer (hPlx->hWD, &trans);
  464.     }
  465. }
  466.  
  467. DWORD P9080_ReadDWord (P9080_HANDLE hPlx, P9080_ADDR addrSpace, DWORD dwOffset)
  468. {
  469.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  470.     {
  471.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  472.         DWORD *pDword = (DWORD *) dwAddr;
  473.         return *pDword;
  474.     }
  475.     else
  476.     {
  477.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  478.         WD_TRANSFER trans;
  479.         BZERO(trans);
  480.         trans.cmdTrans = RP_DWORD;
  481.         trans.dwPort = dwAddr;
  482.         WD_Transfer (hPlx->hWD, &trans);
  483.         return trans.Data.Dword;
  484.     }
  485. }
  486.  
  487. void P9080_WriteDWord (P9080_HANDLE hPlx, P9080_ADDR addrSpace, DWORD dwOffset, DWORD data)
  488. {
  489.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  490.     {
  491.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  492.         DWORD *pDword = (DWORD *) dwAddr;
  493.         *pDword = data;
  494.     }
  495.     else
  496.     {
  497.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  498.         WD_TRANSFER trans;
  499.         BZERO(trans);
  500.         trans.cmdTrans = WP_DWORD;
  501.         trans.dwPort = dwAddr;
  502.         trans.Data.Dword = data;
  503.         WD_Transfer (hPlx->hWD, &trans);
  504.     }
  505. }
  506.  
  507. void P9080_ReadWriteBlock (P9080_HANDLE hPlx, DWORD dwOffset, PVOID buf, 
  508.                     DWORD dwBytes, BOOL fIsRead, P9080_ADDR addrSpace, P9080_MODE mode)
  509. {
  510.     DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  511.     WD_TRANSFER trans;
  512.  
  513.     BZERO(trans);
  514.  
  515.     if (hPlx->addrDesc[addrSpace].fIsMemory) 
  516.     {
  517.         if (fIsRead) 
  518.         {
  519.             if (mode==P9080_MODE_BYTE) trans.cmdTrans = RM_SBYTE;
  520.             else if (mode==P9080_MODE_WORD) trans.cmdTrans = RM_SWORD;
  521.             else trans.cmdTrans = RM_SDWORD;
  522.         }
  523.         else 
  524.         {
  525.             if (mode==P9080_MODE_BYTE) trans.cmdTrans = WM_SBYTE;
  526.             else if (mode==P9080_MODE_WORD) trans.cmdTrans = WM_SWORD;
  527.             else trans.cmdTrans = WM_SDWORD;
  528.         }
  529.     }
  530.     else 
  531.     {
  532.         if (fIsRead) 
  533.         {
  534.             if (mode==P9080_MODE_BYTE) trans.cmdTrans = RP_SBYTE;
  535.             else if (mode==P9080_MODE_WORD) trans.cmdTrans = RP_SWORD;
  536.             else trans.cmdTrans = RP_SDWORD;
  537.         }
  538.         else 
  539.         {
  540.             if (mode==P9080_MODE_BYTE) trans.cmdTrans = WP_SBYTE;
  541.             else if (mode==P9080_MODE_WORD) trans.cmdTrans = WP_SWORD;
  542.             else trans.cmdTrans = WP_SDWORD;
  543.         }
  544.     }
  545.     trans.dwPort = dwAddr;
  546.     trans.fAutoinc = TRUE;
  547.     trans.dwBytes = dwBytes;
  548.     trans.dwOptions = 0;
  549.     trans.Data.pBuffer = buf;
  550.     WD_Transfer (hPlx->hWD, &trans);
  551. }
  552.  
  553. void P9080_ReadBlock (P9080_HANDLE hPlx, DWORD dwOffset, PVOID buf, 
  554.                     DWORD dwBytes, P9080_ADDR addrSpace, P9080_MODE mode)
  555. {
  556.     P9080_ReadWriteBlock (hPlx, dwOffset, buf, dwBytes, TRUE, addrSpace, mode);
  557. }
  558.  
  559. void P9080_WriteBlock (P9080_HANDLE hPlx, DWORD dwOffset, PVOID buf, 
  560.                      DWORD dwBytes, P9080_ADDR addrSpace, P9080_MODE mode)
  561. {
  562.     P9080_ReadWriteBlock (hPlx, dwOffset, buf, dwBytes, FALSE, addrSpace, mode);
  563. }
  564.  
  565. void P9080_SetMode (P9080_HANDLE hPlx, P9080_MODE mode, DWORD dwLocalAddr)
  566. {
  567.     hPlx->addrDesc[hPlx->addrSpace].dwLocalBase = dwLocalAddr & ~hPlx->addrDesc[hPlx->addrSpace].dwMask;
  568.     hPlx->addrDesc[hPlx->addrSpace].dwLocalBase |= BIT0;
  569.     P9080_WriteReg (hPlx, P9080_LAS0BA, hPlx->addrDesc[hPlx->addrSpace].dwLocalBase);
  570. }
  571.  
  572. BYTE P9080_ReadByteLocal (P9080_HANDLE hPlx, DWORD dwLocalAddr)
  573. {
  574.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  575.     P9080_SetMode (hPlx, P9080_MODE_BYTE, dwLocalAddr);
  576.     return P9080_ReadByte(hPlx, hPlx->addrSpace, dwOffset);
  577. }
  578.  
  579. void P9080_WriteByteLocal (P9080_HANDLE hPlx, DWORD dwLocalAddr, BYTE data)
  580. {
  581.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  582.     P9080_SetMode (hPlx, P9080_MODE_BYTE, dwLocalAddr);
  583.     P9080_WriteByte(hPlx, hPlx->addrSpace, dwOffset, data);
  584. }
  585.  
  586. WORD P9080_ReadWordLocal (P9080_HANDLE hPlx, DWORD dwLocalAddr)
  587. {
  588.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  589.     P9080_SetMode (hPlx, P9080_MODE_WORD, dwLocalAddr);
  590.     return P9080_ReadWord(hPlx, hPlx->addrSpace, dwOffset);
  591. }
  592.  
  593. void P9080_WriteWordLocal (P9080_HANDLE hPlx, DWORD dwLocalAddr, WORD data)
  594. {
  595.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  596.     P9080_SetMode (hPlx, P9080_MODE_WORD, dwLocalAddr);
  597.     P9080_WriteWord(hPlx, hPlx->addrSpace, dwOffset, data);
  598. }
  599.  
  600. DWORD P9080_ReadDWordLocal (P9080_HANDLE hPlx, DWORD dwLocalAddr)
  601. {
  602.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  603.     P9080_SetMode (hPlx, P9080_MODE_DWORD, dwLocalAddr);
  604.     return P9080_ReadDWord(hPlx, hPlx->addrSpace, dwOffset);
  605. }
  606.  
  607. void P9080_WriteDWordLocal (P9080_HANDLE hPlx, DWORD dwLocalAddr, DWORD data)
  608. {
  609.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  610.     P9080_SetMode (hPlx, P9080_MODE_DWORD, dwLocalAddr);
  611.     P9080_WriteDWord(hPlx, hPlx->addrSpace, dwOffset, data);
  612. }
  613.  
  614. void P9080_ReadWriteBlockLocal (P9080_HANDLE hPlx, DWORD dwLocalAddr, 
  615.     PVOID buf, DWORD dwBytes, BOOL fIsRead, P9080_MODE mode)
  616. {
  617.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  618.     P9080_SetMode (hPlx, mode, dwLocalAddr);
  619.     P9080_ReadWriteBlock(hPlx, dwOffset, buf, dwBytes, fIsRead, hPlx->addrSpace, mode);
  620. }
  621.  
  622. void P9080_ReadBlockLocal (P9080_HANDLE hPlx, DWORD dwLocalAddr, PVOID buf,
  623.     DWORD dwBytes, P9080_MODE mode)
  624. {
  625.     P9080_ReadWriteBlockLocal (hPlx, dwLocalAddr, buf, dwBytes, TRUE, mode);
  626. }
  627.  
  628. void P9080_WriteBlockLocal (P9080_HANDLE hPlx, DWORD dwLocalAddr, PVOID buf, 
  629.                      DWORD dwBytes, P9080_MODE mode)
  630. {
  631.     P9080_ReadWriteBlockLocal (hPlx, dwLocalAddr, buf, dwBytes, FALSE, mode);
  632. }
  633.  
  634. BOOL P9080_IntIsEnabled (P9080_HANDLE hPlx)
  635. {
  636.     if (!hPlx->fUseInt) return FALSE;
  637.     if (!hPlx->Int.hThread) return FALSE;
  638.     return TRUE;
  639. }
  640.  
  641. VOID P9080_IntHandler (PVOID pData)
  642. {
  643.     P9080_HANDLE hPlx = (P9080_HANDLE) pData;
  644.     P9080_INT_RESULT intResult;
  645.     intResult.dwCounter = hPlx->Int.Int.dwCounter;
  646.     intResult.dwLost = hPlx->Int.Int.dwLost;
  647.     intResult.fStopped = hPlx->Int.Int.fStopped;
  648.     intResult.dwStatusReg = hPlx->Int.Trans[0].Data.Dword;
  649.     hPlx->Int.funcIntHandler(hPlx, &intResult);  
  650. }
  651.  
  652. BOOL P9080_IntEnable (P9080_HANDLE hPlx, P9080_INT_HANDLER funcIntHandler)
  653. {
  654.     DWORD dwIntStatus;
  655.     DWORD dwAddr;
  656.  
  657.     if (!hPlx->fUseInt) return FALSE;
  658.     // check if interrupt is already enabled
  659.     if (hPlx->Int.hThread) return FALSE;
  660.  
  661.     dwIntStatus = P9080_ReadReg (hPlx, P9080_INTCSR);
  662.  
  663.     BZERO(hPlx->Int.Trans);
  664.     // This is a samlpe of handling interrupts:
  665.     // Two transfer commands are issued. First the value of the interrrupt control/status
  666.     // register is read. Then, a value of ZERO is written.
  667.     // This will cancel interrupts after the first interrupt occurs.
  668.     // When using interrupts, this section will have to change:
  669.     // you must put transfer commands to CANCEL the source of the interrupt, otherwise, the 
  670.     // PC will hang when an interrupt occurs!
  671.     dwAddr = hPlx->addrDesc[P9080_ADDR_REG].dwAddr + P9080_INTCSR;
  672.     hPlx->Int.Trans[0].cmdTrans = hPlx->addrDesc[P9080_ADDR_REG].fIsMemory ? RM_DWORD : RP_DWORD;
  673.     hPlx->Int.Trans[0].dwPort = dwAddr;
  674.     hPlx->Int.Trans[1].cmdTrans = hPlx->addrDesc[P9080_ADDR_REG].fIsMemory ? WM_DWORD : WP_DWORD;
  675.     hPlx->Int.Trans[1].dwPort = dwAddr;
  676.     hPlx->Int.Trans[1].Data.Dword = dwIntStatus & ~(BIT8|BIT10); // put here the data to write to the control register
  677.     hPlx->Int.Int.dwCmds = 2; 
  678.     hPlx->Int.Int.Cmd = hPlx->Int.Trans;
  679.     hPlx->Int.Int.dwOptions |= INTERRUPT_CMD_COPY;
  680.  
  681.     // this calls WD_IntEnable() and creates an interrupt handler thread
  682.     hPlx->Int.funcIntHandler = funcIntHandler;
  683.     if (!InterruptThreadEnable(&hPlx->Int.hThread, hPlx->hWD, &hPlx->Int.Int, P9080_IntHandler, (PVOID) hPlx))
  684.         return FALSE;
  685.  
  686.     // this physically enables interrupts
  687.     P9080_WriteReg (hPlx, P9080_INTCSR, dwIntStatus | (BIT8|BIT10));
  688.  
  689.     return TRUE;
  690. }
  691.  
  692. void P9080_IntDisable (P9080_HANDLE hPlx)
  693. {
  694.     DWORD dwIntStatus;
  695.  
  696.     if (!hPlx->fUseInt) return;
  697.     if (!hPlx->Int.hThread) return;
  698.  
  699.     // this disables interrupts
  700.     dwIntStatus = P9080_ReadReg (hPlx, P9080_INTCSR);
  701.     P9080_WriteReg (hPlx, P9080_INTCSR, dwIntStatus & ~(BIT8|BIT10));
  702.  
  703.     // this calls WD_IntDisable()
  704.     InterruptThreadDisable(hPlx->Int.hThread);
  705.     hPlx->Int.hThread = NULL;
  706. }
  707.  
  708. P9080_DMA_HANDLE P9080_DMAOpen (P9080_HANDLE hPlx, DWORD dwLocalAddr, PVOID buf, 
  709.     DWORD dwBytes, BOOL fIsRead, P9080_MODE mode, P9080_DMA_CHANNEL dmaChannel)
  710. {
  711.     DWORD dwDMAMODE, dwDMADPR, dwDMALADR;
  712.     DWORD dwChannelShift = (dmaChannel==P9080_DMA_CHANNEL_0) ? 0 : P9080_DMA_CHANNEL_SHIFT;
  713.     BOOL fAutoinc = TRUE;
  714.     P9080_DMA_HANDLE hDma;
  715.     
  716.     hDma = malloc (sizeof(P9080_DMA_STRUCT));
  717.     if (hDma==NULL)
  718.     {
  719.         sprintf( P9080_ErrorString, "Failed allocating memory for dma handle!\n");
  720.         goto Exit;
  721.     }
  722.     BZERO (*hDma);
  723.     hDma->dmaChannel = dmaChannel;
  724.     hDma->dma.dwBytes = dwBytes;
  725.     hDma->dma.pUserAddr = buf; 
  726.     hDma->dma.dwOptions = 0; 
  727.     WD_DMALock (hPlx->hWD, &hDma->dma);
  728.     if (!hDma->dma.hDma) 
  729.     {
  730.         sprintf( P9080_ErrorString, "Failed locking the buffer!\n");
  731.         goto Exit;
  732.     }
  733.     if (hDma->dma.dwPages==1)
  734.     {
  735.         //dma of one page ==> direct dma
  736.         dwDMAMODE = 
  737.             (fAutoinc ? 0 : BIT11) 
  738.             | BIT6 
  739.             | (mode==P9080_MODE_BYTE ? 0 : mode==P9080_MODE_WORD ? BIT0 : (BIT1 | BIT0));
  740.         dwDMADPR = BIT0 | (fIsRead ? BIT3 : 0);
  741.         dwDMALADR = dwLocalAddr;
  742.  
  743.         P9080_WriteReg (hPlx, P9080_DMAMODE + dwChannelShift, dwDMAMODE);
  744.         P9080_WriteReg (hPlx, P9080_DMAPADR + dwChannelShift, (DWORD) hDma->dma.Page[0].pPhysicalAddr);
  745.         P9080_WriteReg (hPlx, P9080_DMALADR + dwChannelShift, dwDMALADR);
  746.         P9080_WriteReg (hPlx, P9080_DMASIZ + dwChannelShift, hDma->dma.Page[0].dwBytes);
  747.         P9080_WriteReg (hPlx, P9080_DMADPR + dwChannelShift, dwDMADPR);
  748.     }
  749.     else
  750.     {
  751.         DWORD dwAlignShift, dwPageNumber, dwMemoryCopied;
  752.         typedef struct {
  753.             DWORD dwPADR;
  754.             DWORD dwLADR;
  755.             DWORD dwSIZ;
  756.             DWORD dwDPR;
  757.         } DMA_LIST;
  758.         DMA_LIST *pList;
  759.  
  760.         //dma of more then one page ==> chain dma
  761.         hDma->dmaList.dwBytes = hDma->dma.dwPages * sizeof(DMA_LIST) + 0x10; // includes extra 0x10 bytes for quadword alignment
  762.         hDma->dmaList.pUserAddr = NULL;
  763.         hDma->dmaList.dwOptions = DMA_KERNEL_BUFFER_ALLOC;
  764.         WD_DMALock (hPlx->hWD, &hDma->dmaList);
  765.         if (!hDma->dmaList.hDma)
  766.         {
  767.             sprintf (P9080_ErrorString, "Failed locking the chain buffer!\n");
  768.             goto Exit;
  769.         }
  770.  
  771.         //setting chain of dma pages in the memory
  772.         dwMemoryCopied = 0;
  773.         dwAlignShift = 0x10 - (DWORD) hDma->dmaList.pUserAddr & 0xf;  
  774.         // verifcation that bits 0-3 are zero (quadword aligned)
  775.         pList = (DMA_LIST *) ((DWORD) hDma->dmaList.pUserAddr + dwAlignShift);
  776.         for (dwPageNumber=0; dwPageNumber<hDma->dma.dwPages; dwPageNumber++)
  777.         {
  778.             pList[dwPageNumber].dwPADR = (DWORD) hDma->dma.Page[dwPageNumber].pPhysicalAddr;
  779.             pList[dwPageNumber].dwLADR = dwLocalAddr + (fAutoinc ? dwMemoryCopied : 0);
  780.             pList[dwPageNumber].dwSIZ = hDma->dma.Page[dwPageNumber].dwBytes;
  781.             pList[dwPageNumber].dwDPR = 
  782.                 ((DWORD) hDma->dmaList.Page[0].pPhysicalAddr + dwAlignShift + sizeof(DMA_LIST)*(dwPageNumber+1))
  783.                 | BIT0 | (fIsRead ? BIT3 : 0);
  784.             dwMemoryCopied += hDma->dma.Page[dwPageNumber].dwBytes;
  785.         }
  786.         pList[dwPageNumber - 1].dwDPR |= BIT1; // mark end of chain
  787.     
  788.         dwDMAMODE = (fAutoinc ? 0 : BIT11) 
  789.                     | BIT6
  790.                     | BIT9        // chain transfer
  791.                     | (mode==P9080_MODE_BYTE ? 0 : mode==P9080_MODE_WORD ? BIT0 : (BIT1 | BIT0));
  792.         dwDMADPR = ((DWORD)hDma->dmaList.Page[0].pPhysicalAddr + dwAlignShift) | BIT0; 
  793.         // starting the dma
  794.         P9080_WriteReg (hPlx, P9080_DMAMODE + dwChannelShift, dwDMAMODE);
  795.         P9080_WriteReg (hPlx, P9080_DMADPR + dwChannelShift, dwDMADPR);
  796.     }
  797.  
  798.     return hDma;
  799.  
  800. Exit:
  801.     if (hDma!=NULL)
  802.         P9080_DMAClose(hPlx,hDma);
  803.     return NULL;
  804. }
  805.  
  806. void P9080_DMAClose (P9080_HANDLE hPlx, P9080_DMA_HANDLE hDma)
  807. {
  808.     if (hDma->dma.hDma)
  809.         WD_DMAUnlock(hPlx->hWD, &hDma->dma);
  810.     if (hDma->dmaList.hDma)
  811.         WD_DMAUnlock(hPlx->hWD, &hDma->dmaList);
  812.     free (hDma);
  813. }
  814.  
  815. BOOL P9080_DMAIsDone (P9080_HANDLE hPlx, P9080_DMA_HANDLE hDma)
  816. {
  817.     return (P9080_ReadByte(hPlx, P9080_ADDR_REG, P9080_DMACSR + 
  818.         hDma->dmaChannel) & BIT4) == BIT4;
  819. }
  820.  
  821. void P9080_DMAStart (P9080_HANDLE hPlx, P9080_DMA_HANDLE hDma, BOOL fBlocking)
  822. {
  823.     P9080_WriteByte(hPlx, P9080_ADDR_REG, P9080_DMACSR + hDma->dmaChannel, 
  824.         BIT0 | BIT1);
  825.  
  826.     //Busy wait for plx to finish transfer
  827.     if (fBlocking) 
  828.         while (!P9080_DMAIsDone(hPlx, hDma));
  829. }
  830.  
  831. BOOL P9080_DMAReadWriteBlock (P9080_HANDLE hPlx, DWORD dwLocalAddr, PVOID buf, 
  832.     DWORD dwBytes, BOOL fIsRead, P9080_MODE mode, P9080_DMA_CHANNEL dmaChannel)
  833. {
  834.     P9080_DMA_HANDLE hDma;
  835.     if (dwBytes==0) 
  836.         return TRUE;
  837.  
  838.     hDma = P9080_DMAOpen(hPlx, dwLocalAddr, buf, dwBytes, fIsRead, mode, dmaChannel);
  839.     if (!hDma) 
  840.         return FALSE;
  841.  
  842.     P9080_DMAStart(hPlx, hDma, TRUE);
  843.     P9080_DMAClose(hPlx, hDma);
  844.     return TRUE;
  845. }
  846.  
  847. void P9080_EEPROMDelay(P9080_HANDLE hPlx)
  848. {
  849.     WD_SLEEP sleep;
  850.     BZERO (sleep);
  851.     sleep.dwMicroSeconds = 500;
  852.     WD_Sleep( hPlx->hWD, &sleep);
  853. }
  854.  
  855. void P9080_EEPROMChipSelect(P9080_HANDLE hPlx, BOOL fSelect)
  856. {
  857.     DWORD dwCNTRL = P9080_ReadReg(hPlx, P9080_CNTRL);
  858.     if (fSelect)
  859.         dwCNTRL |= BIT25;
  860.     else
  861.         dwCNTRL &= ~BIT25;
  862.     P9080_WriteReg(hPlx, P9080_CNTRL, dwCNTRL);
  863.     P9080_EEPROMDelay(hPlx);
  864. }
  865.  
  866. BOOL P9080_EEPROMValid(P9080_HANDLE hPlx)
  867. {
  868.     return (P9080_ReadReg(hPlx, P9080_CNTRL) & BIT28)==BIT28;
  869. }
  870.  
  871. void P9080_EEPROMWriteBit(P9080_HANDLE hPlx, BOOL fBit)
  872. {
  873.     DWORD dwCNTRL = P9080_ReadReg(hPlx, P9080_CNTRL);
  874.  
  875.     dwCNTRL &= ~BIT24;
  876.     if (fBit) // data
  877.         dwCNTRL |= BIT26;
  878.     else
  879.         dwCNTRL &= ~BIT26;
  880.     P9080_WriteReg( hPlx, P9080_CNTRL, dwCNTRL);
  881.     P9080_EEPROMDelay(hPlx);
  882.  
  883.     dwCNTRL |= BIT24; // clock
  884.     P9080_WriteReg( hPlx, P9080_CNTRL, dwCNTRL);
  885.     P9080_EEPROMDelay(hPlx);
  886.  
  887.     dwCNTRL &= ~BIT24;
  888.     P9080_WriteReg( hPlx, P9080_CNTRL, dwCNTRL);
  889.     P9080_EEPROMDelay(hPlx);
  890. }
  891.  
  892. BOOL P9080_EEPROMReadBit(P9080_HANDLE hPlx)
  893. {
  894.     BOOL fRet;
  895.     DWORD dwCNTRL = P9080_ReadReg(hPlx, P9080_CNTRL);
  896.  
  897.     dwCNTRL &= ~BIT24;
  898.     P9080_WriteReg( hPlx, P9080_CNTRL, dwCNTRL);
  899.     P9080_EEPROMDelay(hPlx);
  900.  
  901.     dwCNTRL |= BIT24; // clock
  902.     P9080_WriteReg( hPlx, P9080_CNTRL, dwCNTRL);
  903.     P9080_EEPROMDelay(hPlx);
  904.  
  905.     dwCNTRL &= ~BIT24;
  906.     P9080_WriteReg( hPlx, P9080_CNTRL, dwCNTRL);
  907.     P9080_EEPROMDelay(hPlx);
  908.  
  909.     fRet = (P9080_ReadReg( hPlx, P9080_CNTRL) & BIT27)==BIT27;
  910.  
  911.     return fRet;
  912. }
  913.  
  914. void P9080_EEPROMWriteEnableDisable(P9080_HANDLE hPlx, BOOL fEnable)
  915. {
  916.     P9080_EEPROMChipSelect(hPlx, TRUE);
  917.  
  918.     // send a WEN instruction
  919.     P9080_EEPROMWriteBit(hPlx, 1);
  920.     P9080_EEPROMWriteBit(hPlx, 0);
  921.     P9080_EEPROMWriteBit(hPlx, 0);
  922.     P9080_EEPROMWriteBit(hPlx, fEnable ? 1 : 0);
  923.     P9080_EEPROMWriteBit(hPlx, fEnable ? 1 : 0);
  924.  
  925.     P9080_EEPROMWriteBit(hPlx, 0);
  926.     P9080_EEPROMWriteBit(hPlx, 0);
  927.     P9080_EEPROMWriteBit(hPlx, 0);
  928.     P9080_EEPROMWriteBit(hPlx, 0);
  929.  
  930.     P9080_EEPROMChipSelect(hPlx, FALSE);
  931. }
  932.  
  933. BOOL P9080_EEPROMReadWord(P9080_HANDLE hPlx, DWORD dwOffset, PWORD pwData)
  934. {
  935.     DWORD dwAddr = dwOffset >> 1;
  936.     DWORD i;
  937.  
  938.     *pwData = 0;
  939.  
  940.     P9080_EEPROMChipSelect(hPlx, TRUE);
  941.     P9080_EEPROMWriteBit(hPlx, 1);
  942.     P9080_EEPROMWriteBit(hPlx, 1);
  943.     P9080_EEPROMWriteBit(hPlx, 0);
  944.      // if it's a CS46 EEPROM send only 5 bit address
  945.     for ( i = hPlx->fUseCS46EEPROM ? BIT5 : BIT7; i; i = i>>1)
  946.     {
  947.         P9080_EEPROMWriteBit(hPlx, (dwAddr & i) == i);
  948.     }
  949.     for (i=BIT15; i; i = i>>1)
  950.     {
  951.         *pwData |= P9080_EEPROMReadBit(hPlx) ? i : 0;
  952.     }
  953.  
  954.     P9080_EEPROMWriteEnableDisable(hPlx, FALSE);
  955.     
  956.     return TRUE;
  957. }
  958.  
  959. BOOL P9080_EEPROMWriteWord(P9080_HANDLE hPlx, DWORD dwOffset, WORD wData)
  960. {
  961.     DWORD dwAddr = dwOffset >> 1;
  962.     DWORD i;
  963.     WORD readback;
  964.  
  965.     P9080_EEPROMWriteEnableDisable(hPlx, TRUE);
  966.  
  967.     P9080_EEPROMChipSelect(hPlx, TRUE);
  968.  
  969.     // send a PRWRITE instruction
  970.     P9080_EEPROMWriteBit(hPlx, 1);
  971.     P9080_EEPROMWriteBit(hPlx, 0);
  972.     P9080_EEPROMWriteBit(hPlx, 1);
  973.     // if it's a CS46 EEPROM send only a 6 bit address
  974.     for ( i = hPlx->fUseCS46EEPROM ? BIT5 : BIT7; i; i = i>>1)
  975.     {
  976.         P9080_EEPROMWriteBit(hPlx, (dwAddr & i) == i);
  977.     }
  978.     for (i=BIT15; i; i = i>>1)
  979.     {
  980.         P9080_EEPROMWriteBit(hPlx, (wData & i) == i);
  981.     }
  982.  
  983.     P9080_EEPROMChipSelect(hPlx, FALSE);
  984.     
  985.     P9080_EEPROMWriteEnableDisable(hPlx, FALSE);
  986.  
  987.     if (P9080_EEPROMReadWord(hPlx, dwOffset, &readback))
  988.     {
  989.         if (wData != readback)
  990.         {
  991.             sprintf( P9080_ErrorString, "Write 0x%04x, Read 0x%04x\n", wData, readback);
  992.             return FALSE;
  993.         }
  994.     }
  995.     else
  996.         return FALSE;
  997.  
  998.     return TRUE;
  999. }
  1000.  
  1001. BOOL P9080_EEPROMReadDWord(P9080_HANDLE hPlx, DWORD dwOffset, PDWORD pdwData)
  1002. {
  1003.     WORD wData1, wData2;
  1004.     if (dwOffset % 4)
  1005.     {
  1006.         sprintf( P9080_ErrorString, "The offset is not a multiple of 4\n");
  1007.         return FALSE;
  1008.     }
  1009.  
  1010.     if (!P9080_EEPROMReadWord(hPlx, dwOffset, &wData1))
  1011.         return FALSE;
  1012.     if (!P9080_EEPROMReadWord(hPlx, dwOffset+2, &wData2))
  1013.         return FALSE;
  1014.  
  1015.     *pdwData = (DWORD) ((wData1 << 16) + wData2);
  1016.     return TRUE;
  1017. }
  1018.  
  1019. BOOL P9080_EEPROMWriteDWord(P9080_HANDLE hPlx, DWORD dwOffset, DWORD dwData)
  1020. {
  1021.     WORD wData1, wData2;
  1022.  
  1023.     if (dwOffset % 4)
  1024.     {
  1025.         sprintf( P9080_ErrorString, "The offset is not a multiple of 4\n");
  1026.         return FALSE;
  1027.     }
  1028.  
  1029.     wData1 = (WORD) (dwData >> 16);
  1030.     wData2 = (WORD) (dwData & 0xffff);
  1031.  
  1032.     if (!P9080_EEPROMWriteWord(hPlx, dwOffset, wData1))
  1033.         return FALSE;
  1034.     if (!P9080_EEPROMWriteWord(hPlx, dwOffset+2, wData2))
  1035.         return FALSE;
  1036.  
  1037.     return TRUE;
  1038. }
  1039.                                       
  1040.